package com.cloudsea.yunhaistores.service.impl;


import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.lang.Snowflake;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cloudsea.yunhaistores.dto.LoginDTO;
import com.cloudsea.yunhaistores.dto.MerchantInfoDTO;
import com.cloudsea.yunhaistores.dto.MerchantRegisterDTO;
import com.cloudsea.yunhaistores.entity.MerchantUsers;
import com.cloudsea.yunhaistores.entity.Merchants;
import com.cloudsea.yunhaistores.mapper.MerchantUsersMapper;
import com.cloudsea.yunhaistores.mapper.MerchantsMapper;
import com.cloudsea.yunhaistores.service.MerchantService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.UUID;

@Service
public class MerchantServiceImpl implements MerchantService {
    @Autowired
    private MerchantsMapper merchantsMapper;

    @Autowired
    private MerchantUsersMapper merchantUsersMapper;

    /**
     * 注入我们在 SnowflakeIdConfig 中配置的 Snowflake Bean
     */
    @Autowired
    private Snowflake snowflake;

    /**
     * 商户注册
     * <p>
     * 使用 @Transactional 注解确保方法内的所有数据库操作要么全部成功，
     * 要么在发生任何异常时全部回滚，从而保证数据的一致性。
     *
     * @param dto 包含注册信息的DTO对象
     */
    @Override
    @Transactional
    public void register(MerchantRegisterDTO dto) {
        // 步骤 1: 检查手机号是否已作为主要联系方式被注册，防止重复注册。
        QueryWrapper<Merchants> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("contact_phone", dto.getContactPhone());
        if (merchantsMapper.selectCount(queryWrapper) > 0) {
            // 如果手机号已存在，则抛出异常，后续操作将不会执行。
            throw new RuntimeException("该手机号已被注册");
        }

        // 步骤 2: 创建商户主体 (merchants 表)
        Merchants merchant = new Merchants();

        // 核心改动：在插入前，使用雪花算法生成唯一的ID并设置给实体。
        merchant.setId(snowflake.nextId());

        merchant.setMerchantNo("M" + UUID.randomUUID().toString().replace("-", ""));
        merchant.setMerchantName(dto.getMerchantName());
        merchant.setContactPhone(dto.getContactPhone());
        merchant.setStatus(0); // 初始状态设置为 0:待审核
        merchant.setCreatedAt(LocalDateTime.now());
        merchant.setUpdatedAt(LocalDateTime.now());

        // 插入商户数据到数据库
        merchantsMapper.insert(merchant);

        // 步骤 3: 为该商户创建一个默认的管理员账号 (merchant_users 表)
        MerchantUsers adminUser = new MerchantUsers();

        // 核心改动：同样为用户账号生成一个唯一的雪花ID。
        adminUser.setId(snowflake.nextId());

        // 将此管理员账号关联到刚刚创建的商户ID。
        adminUser.setMerchantId(merchant.getId());

        // 默认使用手机号作为管理员的登录名。
        adminUser.setUsername(dto.getContactPhone());
        //为该用户生成一个随机的、唯一的盐值
        String salt = UUID.randomUUID().toString();

        // 安全措施：绝不能存储明文密码！使用 Sa-Token 提供的工具进行加盐MD5哈希。
        String hashedPassword = SaSecureUtil.md5BySalt(dto.getPassword(), salt);

        //将加密后的哈希值和盐值分别存入实体对象
        adminUser.setPasswordHash(hashedPassword);
        adminUser.setSalt(salt);

        adminUser.setRole("admin"); // 设置角色为 'admin'
        adminUser.setStatus(1); // 账号状态设置为 1:启用
        adminUser.setCreatedAt(LocalDateTime.now());

        // 插入管理员账号数据到数据库
        merchantUsersMapper.insert(adminUser);
    }

    @Override
    public SaTokenInfo login(LoginDTO dto) {
        // 1. 根据用户名（手机号）查找用户
        QueryWrapper<MerchantUsers> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", dto.getUsername());
        MerchantUsers user = merchantUsersMapper.selectOne(queryWrapper);

        // 2. 处理用户不存在的情况
        if (user == null) {
            throw new RuntimeException("用户名或密码错误");
        }

        // 3. 校验账号状态
        if (user.getStatus() != 1) {
            throw new RuntimeException("账号已被禁用，请联系平台");
        }

        // 4. 验证密码
        // 使用存放在数据库里的盐，对用户本次输入的密码进行相同的哈希计算
        String hashedPassword = SaSecureUtil.md5BySalt(dto.getPassword(), user.getSalt());

        // 将计算出的哈希值与数据库中存储的哈希值进行比对
        if (!hashedPassword.equals(user.getPasswordHash())) {
            // 如果不匹配，则密码错误
            throw new RuntimeException("用户名或密码错误");
        }

        // 5. 密码验证通过，使用 Sa-Token 执行登录
        // 这会在服务端创建一个会话，并生成一个Token
        StpUtil.login(user.getId());

        // 6. 获取并返回生成的 Token 信息
        return StpUtil.getTokenInfo();
    }

    @Override
    public MerchantInfoDTO getCurrentMerchantInfo() {
        // 1. 从 Sa-Token 获取当前登录用户的ID
        long loginId = StpUtil.getLoginIdAsLong();

        // 2. 根据用户ID查询用户信息
        MerchantUsers user = merchantUsersMapper.selectById(loginId);
        if (user == null) {
            // 理论上，已登录的用户不可能在数据库中找不到，但做好防御性编程
            throw new RuntimeException("当前用户信息异常，请重新登录");
        }

        // 3. 根据用户信息中的 merchantId 查询商户信息
        Merchants merchant = merchantsMapper.selectById(user.getMerchantId());
        if (merchant == null) {
            throw new RuntimeException("所属商户信息异常");
        }

        // 4. 将查询到的信息组装到 DTO 中
        MerchantInfoDTO dto = new MerchantInfoDTO();
        dto.setUserId(user.getId());
        dto.setUsername(user.getUsername());
        dto.setFullName(user.getFullName());
        dto.setRole(user.getRole());
        dto.setMerchantId(merchant.getId());
        dto.setMerchantName(merchant.getMerchantName());
        dto.setMerchantNo(merchant.getMerchantNo());

        // 5. 返回组装好的DTO
        return dto;
    }

    @Override
    public void logout() {
        // 只需调用 Sa-Token 的静态工具方法即可
        // 它会自动获取当前请求的Token，并将其注销
        StpUtil.logout();
    }
}
